// run: $exec < input
// opt: 0
// flag: -g
#include <cstdio>
#include <algorithm>

int const maxn = 300007;

struct node
{
	void push_down();
	void update()
	{
		push_down(); child[0]->push_down(); child[1]->push_down();
		max = std::max(value, std::max(child[0]->max, child[1]->max));
	}

	int value, max, delta;
	bool rev;
	node * parent, * child[2];
} memory[maxn], *nil = memory;

void inc(node * u, int d)
{
	if (u == nil) return;
	u->delta += d; u->value += d; u->max += d;
}

void node::push_down()
{
	if (this == nil) return;
	if (delta) {
		inc(child[0], delta);
		inc(child[1], delta);
		delta = 0;
	}
	if (rev) {
		std::swap(child[0], child[1]);
		child[0]->rev ^= true;
		child[1]->rev ^= true;
		rev = false;
	}
}

void init(int n)
{
	for (int i = 0; i <= n; i++) {
		memory[i].parent = memory[i].child[0] = memory[i].child[1] = nil;
		memory[i].value = memory[i].delta = memory[i].max = 0;
		memory[i].rev = false;
	}
}

void rotate(node * u, int is_left)
{
	node * p = u->parent;
	p->child[!is_left] = u->child[is_left];
	if (u->child[is_left] != nil) u->child[is_left]->parent = p;
	u->parent = p->parent;
	if (p->parent->child[0] == p) u->parent->child[0] = u;
	else if (p->parent->child[1] == p) u->parent->child[1] = u;
	u->child[is_left] = p;
	p->parent = u;
	p->update();

}

void splay(node * u)
{
	if (u == nil) return;
	u->push_down();
	for (node *v, *w; (v = u->parent) != nil && (v->child[0] == u || v->child[1] == u); ) {
		if ((w = v->parent) != nil && (w->child[0] == v || w->child[1] == v)) {
			w->push_down(); v->push_down(); u->push_down();
			bool is_left = v == v->parent->child[0];
			if (u == v->child[is_left]) {
				rotate(u, !is_left); rotate(u, is_left);
			} else {
				rotate(v, is_left); rotate(u, is_left);
			}
		} else {
			v->push_down(); u->push_down();
			rotate(u, u == v->child[0]);
			break;
		}
	}
	u->update();
}

node * access(node * u)
{
	node * v = nil;
	for (; u != nil; v = u, u = u->parent) {
		splay(u);
		u->child[1] = v;
	}
	return v;
}

void make_root(node * u)
{
	access(u)->rev ^= true;
	splay(u);
}

node * get_root(node * u)
{
	for (u = access(u); u->push_down(), u->child[0] != nil; u = u->child[0]);
	return u;
}

void link(node * u, node * v)
{
	make_root(u);
	u->parent = v;
	access(u);
}

void cut(node * u, node * v)
{
	make_root(u);
	access(v);
	splay(v);
	v->child[0]->parent = nil;
	v->child[0] = nil;
	v->update();
}

int query_max(node * u, node * v)
{
	make_root(u);
	access(v);
	splay(v);
	return v->max;
}

void add(node * u, node * v, int d)
{
	make_root(u);
	access(v);
	splay(v);
	inc(v, d);
}

int main()
{
	for (int n; std::scanf("%d", &n) != EOF; ) {
		init(n);

		// input tree
		for (int i = 1, x, y; i < n; i++) {
			std::scanf("%d %d", &x, &y);
			link(memory + x, memory + y);
		}

		// input node value
		for (int i = 1, x; i <= n; i++) {
			std::scanf("%d", &x);
			node * node = memory + i;
			splay(node);
			node->value = node->max = x;
			node->update();
		}

		// query
		int m;
		std::scanf("%d", &m);
		for (int i = 0, op, x, y, z; i < m; i++) {
			std::scanf("%d %d %d", &op, &x, &y);
			switch (op) {
				case 1:
					if (get_root(memory + x) == get_root(memory + y)) std::printf("-1\n");
					else link(memory + x, memory + y); break;
				case 2:
					if (x == y || get_root(memory + x) != get_root(memory + y)) std::printf("-1\n");
					else cut(memory + x, memory + y); break;
				case 3:
					std::scanf("%d", &z);
					if (get_root(memory + y) != get_root(memory + z)) std::printf("-1\n");
					else add(memory + y, memory + z, x); break;
				case 4:
					if (get_root(memory + x) != get_root(memory + y)) std::printf("-1\n");
					else std::printf("%d\n", query_max(memory + x, memory + y));
			}
		}
		std::printf("\n");
	}
}

